
const moment = require('moment');
const xlsx = require('node-xlsx');
const fs = require('fs');
import { Config } from '@midwayjs/decorator';
import { Provide, Inject } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';
import { ProjectRecordModel } from '../entity/project_records.methods';
import { ProjectOrderContactModel } from '../entity/project_order_contact.methods';
import { WorkingRecordsModel } from '../entity/working_records.methods';
import { OapiDingtalk } from '../utils/oapi.dingtalk'
import { DingtalkAuthService } from './dingtalk.auth.service'
import { UserService } from './user.service'

@Provide()
export class WorkingService {
  @Config('tempfile')
  tempfile: any;

  @Inject()
  ctx: Context;

  @Inject()
  ProjectRecordModel: ProjectRecordModel;

  @Inject()
  ProjectOrderContactModel: ProjectOrderContactModel;

  @Inject()
  WorkingRecordsModel: WorkingRecordsModel;

  @Inject()
  ddTopOapi: OapiDingtalk;

  @Inject()
  DingtalkAuthService: DingtalkAuthService;

  @Inject()
  UserService: UserService;

  /**
   * 创建工时登记信息
   * @param {*} workTitle 工时填报单名称 
   * @param {*} startTime 工时开始日期
   * @param {*} endTime 工时结束日期
   * @param {*} workArray 工时详情数组
   * @param {*} workAmount 工时数量
   * @param {*} projectsId 项目id
   * @param {*} remarks 备注
   * @returns 
   */
  async createdWorking(params: any): Promise<any> {
    const { ctx } = this;
    const userInfo = ctx.userInfo;
    const { workTitle, startTime, endTime, workArray } = params;
    const successRes = [];
    const errorRes = [];
    for (let i = 0; i < workArray.length; i++) {
      const el = workArray[i];
      const projInfo = await this.ProjectRecordModel.getProjById(el.projectsId);
      if (projInfo && projInfo[0]) {
        const res = await this.WorkingRecordsModel.insertWorking({
          hoursAmount: userInfo.hours_amount || 0,
          userNick: userInfo.nick,
          unionId: userInfo.union_id,
          workTitle: workTitle,
          startTime: startTime,
          endTime: endTime,
          workAmount: el.workAmount,
          projectsName: projInfo[0].project_name || "",
          projectsId: el.projectsId,
          remarks: el.remarks || ""
        });
        successRes.push(res);
      } else {
        errorRes.push({ msg: "项目信息不存在", ...el })
      }
    }
    return { successRes, errorRes }
  }

  /**
   * 工时信息分页查询
   * @param {*} params 
   */
  async getWorkingPage(params: any): Promise<any> {
    const { ctx } = this;
    const userInfo = ctx.userInfo;
    const { pageNum, pageSize } = params;
    const total = await this.WorkingRecordsModel.getTotalNum(userInfo.union_id);
    const res = {
      total: total[0].num,
      lists: []
    }
    if (total[0].num) {
      const resList = await this.WorkingRecordsModel.getDataByPage(pageNum, pageSize, userInfo.union_id);
      res.lists = resList;
    }
    return res
  }

  /**
   * 更新工时登记信息
   * @param {*} id 工时填报单id
   * @param {*} workTitle 工时填报单名称 
   * @param {*} startTime 工时开始日期
   * @param {*} endTime 工时结束日期
   * @param {*} workAmount 工时数量
   * @param {*} projectsId 项目id
   * @param {*} remarks 备注
   * @returns 
   */
  async updateWorking(params: any): Promise<any> {
    const projInfo = await this.ProjectRecordModel.getProjById(params.projectsId);
    if (!projInfo || !projInfo.length) return Promise.reject("项目信息不存在")

    await this.WorkingRecordsModel.updateWorkingById({
      id: params.id,
      workTitle: params.workTitle,
      startTime: params.startTime,
      endTime: params.endTime,
      workAmount: params.workAmount,
      projectsName: projInfo[0].project_name,
      projectsId: params.projectsId,
      remarks: params.remarks
    });

    return "更新成功";
  }

  /**
   * 删除项目数据
   * @param {*} id
   */
  async delWorking(params: { id: number }): Promise<any> {
    await this.WorkingRecordsModel.delWorkingById(params.id);
    return "删除成功"
  }


  /**
   * 管理员查询 获取全部工时汇总
   * @param {*} pageNum   当前页码
   * @param {*} pageSize  每页条数
   * @param {*} searchKey 搜索内容
   * @param {*} deptId    部门id
   */
  async getAdminWorkingPage(params: { pageNum: number, pageSize: number, searchKey: any, deptId: any }): Promise<any> {

    const { pageNum, pageSize, searchKey, deptId } = params;

    if (deptId) {
      // 部门查询
      return await this.getAdminWorkingPageByDeptId(params)
    } else {
      //  普通查询
      const total = await this.WorkingRecordsModel.getAdminTotalNum(searchKey);
      const res = {
        total: total[0].num,
        lists: []
      }
      if (total[0].num) {
        const resList = await this.WorkingRecordsModel.getAdminDataByPage(pageNum, pageSize, searchKey);
        res.lists = resList;
      }
      return res;
    }
  }
  //  根据查询当前部门下所有用户的工时汇总
  async getAdminWorkingPageByDeptId(params: any): Promise<any> {
    const { pageNum, pageSize, searchKey, deptId } = params;

    // 获取应用token
    const appToken = await this.DingtalkAuthService.getAppToken();
    if (!appToken || !appToken.success) return Promise.reject("获取应用token失败")

    //  获取当前部门下的用户id
    const userIds = await this.getUserListsByDeptId(deptId, appToken.accessToken);

    if (!userIds || !userIds.length) {
      return { total: 0, lists: [] }
    }

    const total = await this.WorkingRecordsModel.getAdminTotalNumByDeptId(searchKey, userIds);
    const res = {
      total: total[0].num,
      lists: []
    }

    if (total[0].num) {
      const resList = await this.WorkingRecordsModel.getAdminDataByPageByDeptId(pageNum, pageSize, searchKey, userIds);
      res.lists = resList;
    }
    return res;
  }

  /**
   * 根据部门id获取部门下所有用户信息
   * @param {*} deptId 
   * @param {*} appToken 
   * @returns 
   */
  async getUserListsByDeptId(deptId: any, appToken: any): Promise<any> {
    //  获取部门用户基础信息
    let _userIds = await this.getUserIds(deptId, appToken);
    //  查询当前部门是否还有子部门存在
    // 一级
    const _firstDept = await this.ddTopOapi.queryDepartmentListsubid(deptId, appToken);
    if (_firstDept.success && _firstDept.dept_id_list && _firstDept.dept_id_list.length) {
      for (let iq = 0; iq < _firstDept.dept_id_list.length; iq++) {
        // 二级
        const _deptid1 = _firstDept.dept_id_list[iq];
        // 获取用户userid
        const _user = await this.getUserIds(_deptid1, appToken);
        _userIds = _userIds.concat(_user);

        const _secondDept = await this.ddTopOapi.queryDepartmentListsubid(_deptid1, appToken);
        if (_secondDept.success && _secondDept.dept_id_list && _secondDept.dept_id_list.length) {
          for (let jq = 0; jq < _secondDept.dept_id_list.length; jq++) {
            // 三级
            const _deptid2 = _secondDept.dept_id_list[jq];
            // 获取用户userid
            const _user2 = await this.getUserIds(_deptid2, appToken);
            _userIds = _userIds.concat(_user2);

            const _thirdDept = await this.ddTopOapi.queryDepartmentListsubid(_deptid2, appToken);
            if (_thirdDept.success && _thirdDept.dept_id_list && _thirdDept.dept_id_list.length) {
              for (let kq = 0; kq < _thirdDept.dept_id_list.length; kq++) {
                // 四级
                const _deptid3 = _thirdDept.dept_id_list[kq];
                // 获取用户userid
                const _user3 = await this.getUserIds(_deptid3, appToken);
                _userIds = _userIds.concat(_user3);
              }
            }
          }
        }
      }
    }

    return _userIds.filter(function (item, index, _userIds) {
      return _userIds.indexOf(item, 0) === index;
    });
  }

  /**
   * 获取部门用户userid
   * @param {*} deptId 
   * @param {*} appToken 
   */
  async getUserIds(deptId: any, appToken: any): Promise<any> {
    const arr = []
    const userLists = await this.ddTopOapi.queryUserListsimple(deptId, appToken);
    if (userLists.success && userLists.list && userLists.list.length) {
      userLists.list.forEach(item => {
        arr.push(item.userid);
      })
    }
    return arr
  }

  /**
   * 设置工时金额
   * @param id  
   * @returns 
   */
  async setWorkAmount(params: {id:number, union_id:string}): Promise<any> {
    const user = await this.UserService.getUserByUnionId(params.union_id);
    if (user.success && user.userInfo) {
      if(!user.userInfo.hours_amount) return Promise.reject("请前往用户管理更新用户金额")
      return await this.WorkingRecordsModel.updateHoursAmountById(params.id, user.userInfo.hours_amount)
    }else{
      return Promise.reject("用户信息不存在")
    }
  }

  /**
   * 管理员查询 工时导出
   * @param params 
   * @returns 
   */
  async downloadAdminWorkingFile(params: { searchKey: any, deptId: any, startTime:any,endTime:any }): Promise<any> {
    const { searchKey, deptId, startTime, endTime } = params;
    let resList = [];
    if (deptId) {
      // 获取应用token
      const appToken = await this.DingtalkAuthService.getAppToken();
      if (!appToken || !appToken.success) return Promise.reject("获取应用token失败")
      // 部门查询
      const userIds = await this.getUserListsByDeptId(deptId, appToken.accessToken);
      if (!userIds || !userIds.length) {
        resList = []
      } else {
        resList = await this.WorkingRecordsModel.downloadAdminDataByDeptId(searchKey, userIds, startTime, endTime);
      }
    } else {
      resList = await this.WorkingRecordsModel.downloadAdminData(searchKey, startTime, endTime);
    }

    const xlsxArr = [
      ["ID", "用户名称", "用户ID", "填报单名称", "工时数量", "项目名称", "项目ID", "备注", "工时开始日期", "工时结束日期", "创建时间", "更新时间"]
    ];

    resList.forEach(ele => {
      xlsxArr.push([
        ele.id, ele.user_nick, ele.union_id, ele.work_title, ele.work_amount, ele.projects_name, ele.projects_id, ele.remarks, ele.start_time, ele.end_time, ele.created_at, ele.updated_at
      ]);
    });
    //由于各列数据长度不同，可以设置一下列宽
    const options = { '!cols': [{ wch: 6 }, { wch: 12 }, { wch: 15 }, { wch: 25 }, { wch: 12 }, { wch: 20 }, { wch: 10 }, { wch: 30 }, { wch: 15 }, { wch: 15 }, { wch: 15 }, { wch: 15 }] }
    //生成表格
    const buffer = xlsx.build([{ name: 'sheet1', data: xlsxArr }], { sheetOptions: options });

    const filename = `export-${moment().format('YYYYMMDD-hhmmss')}.xlsx`;
    const filePath = this.tempfile + "/" + filename; // 存储路劲和文件名
    fs.writeFileSync(filePath, buffer, { 'flag': 'w' });
    this.ctx.attachment(filename);
    //创建可读流
    return fs.createReadStream(filePath);
  }

}
